package mqtt

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/httplib"
	"github.com/goinggo/mapstructure"
)

type mqtt struct {
	Topic    string `json:"topic"`
	Payload  string `json:"payload"`
	Qos      int64  `json:"qos"`
	Retain   bool   `json:"retain"`
	Clientid string `json:"client_id"`
}

const (
	push        = "api/v3/mqtt/publish"
	brokers     = "api/v3/brokers"
	sessions    = "api/v3/sessions/%s"
	connections = "api/v3/connections/%s"
)

var (
	mqttHost      = beego.AppConfig.DefaultString("mqtt_host", "http://mqtt.rcenet.com:18083/")
	mqttAppid     = beego.AppConfig.DefaultString("mqtt_appid", "189ba64e2ec9c")
	mqttAppsecret = beego.AppConfig.DefaultString("mqtt_appsecret", "Mjg2OTY3ODcyNTUzMjAwODg5NjIzMTg5NzM4Mzk5MzM0NDA")
)

//func init()  {
//	mqttHost = beego.AppConfig.DefaultString("mqtt_host", "http://mqtt.rcenet.com:18083/")
//	mqttAppid = beego.AppConfig.DefaultString("mqtt_appid", "189ba64e2ec9c")
//	mqttAppsecret = beego.AppConfig.DefaultString("mqtt_appsecret", "Mjg2OTY3ODcyNTUzMjAwODg5NjIzMTg5NzM4Mzk5MzM0NDA")
//}

func Create() *mqtt {
	mqtt := mqtt{
		Qos:      0,
		Retain:   false,
		Clientid: beego.AppConfig.DefaultString("mqtt_client_id", "server"),
	}
	return &mqtt
}

type ClientSession struct {
	AwaitingRelLen     int64  `json:"awaiting_rel_len"`
	Binding            string `json:"binding"`
	CleanStart         bool   `json:"clean_start"`
	ClientId           string `json:"client_id"`
	CreatedAt          string `json:"created_at"`
	DeliverMsg         int64  `json:"deliver_msg"`
	EnqueueMsg         int64  `json:"enqueue_msg"`
	ExpiryInterval     int64  `json:"expiry_interval"`
	HeapSize           int64  `json:"heap_size"`
	InflightLen        int64  `json:"inflight_len"`
	MailboxLen         int64  `json:"mailbox_len"`
	MaxAwaitingRel     int64  `json:"max_awaiting_rel"`
	MaxInflight        int64  `json:"max_inflight"`
	MaxMqueue          int64  `json:"max_mqueue"`
	MaxSubscriptions   int64  `json:"max_subscriptions"`
	MqueueDropped      int64  `json:"mqueue_dropped"`
	MqueueLen          int64  `json:"mqueue_len"`
	Node               string `json:"node"`
	Reductions         int64  `json:"reductions"`
	SubscriptionsCount int64  `json:"subscriptions_count"`
	Username           string `json:"username"`
}

// 客户端会话信息
func (m *mqtt) ClientSession(client_id string) (*ClientSession, error) {
	onlineUrl := fmt.Sprintf("%s%s", mqttHost, fmt.Sprintf(sessions, client_id))

	session := ClientSession{}
	var js []interface{}
	err := httplib.Get(onlineUrl).SetBasicAuth(mqttAppid, mqttAppsecret).ToJSON(&js)
	if err != nil {
		return nil, err
	}

	if len(js) <= 0 {
		return nil, nil
	}

	err = mapstructure.Decode(js[0], &session)
	if err != nil {
		return nil, err
	}

	return &session, nil
}

type Connection struct {
	CleanStart  bool   `json:"clean_start"`
	ClientId    string `json:"client_id"`
	ConnectedAt string `json:"connected_at"`
	HeapSize    int64  `json:"heap_size"`
	Ipaddress   string `json:"ipaddress"`
	IsBridge    bool   `json:"is_bridge"`
	IsSuper     bool   `json:"is_super"`
	KeepaLive   int64  `json:"keepalive"`
	MailboxLen  int64  `json:"mailbox_len"`
	Mountpoint  string `json:"Mountpoint"`
	Node        string `json:"node"`
	Peercert    string `json:"peercert"`
	Port        int64  `json:"port"`
	ProtoName   string `json:"proto_name"`
	ProtoVer    int64  `json:"proto_ver"`
	Username    string `json:"username"`
	Zone        string `json:"zone"`
	RecvCnt     int64  `json:"recv_cnt"`
	SendMsg     int64  `json:"send_msg"`
}

type ConnResp struct {
	Code int           `json:"code"`
	Data []*Connection `json:"data"`
}

func (m *mqtt) Connection(client_id string) (*Connection, error) {
	onlineUrl := fmt.Sprintf("%s%s",mqttHost, fmt.Sprintf(connections, client_id))

	connResp := &ConnResp{}
	err := httplib.Get(onlineUrl).SetBasicAuth(mqttAppid, mqttAppsecret).ToJSON(connResp)

	if err != nil || len(connResp.Data) < 1 {
		return nil, err
	}

	return connResp.Data[0], nil
}

// 推送消息
func (m *mqtt) Push() error {
	if m.Topic == "" {
		return errors.New("topic Can not be empty")
	}

	bytes, err := json.Marshal(m)
	if err != nil {
		return err
	}

	pushUrl := fmt.Sprintf("%s%s", mqttHost, push)
	resp, err := httplib.Post(pushUrl).SetBasicAuth(mqttAppid, mqttAppsecret).Body(bytes).String()

	if err != nil {
		return err
	}

	if resp != `{"code":0}` {
		return errors.New("push fail")
	}

	return nil
}

func (m *mqtt) SetTopic(topic string) *mqtt {
	m.Topic = topic
	return m
}

func (m *mqtt) SetQos(qos int64) *mqtt {
	m.Qos = qos
	return m
}

func (m *mqtt) SetRetain(retain bool) *mqtt {
	m.Retain = retain
	return m
}

func (m *mqtt) SetClientId(client_id string) *mqtt {
	m.Clientid = client_id
	return m
}

func (m *mqtt) SetPayload(payload string) *mqtt {
	m.Payload = payload
	return m
}
